//备注：拷贝代码请加上作者信息
//作者：王海涛
//邮箱：1126471088@qq.com
//版本：V1.0.0
/********************************************************
    说明：
    1、这个链表是基于 FreeRTOS V9.0.0 版本里的链表修改而来。
**********************************************************/

#include <stdlib.h>
#include "rtos_list.h"


/*-----------------------------------------------------------
 * PUBLIC LIST API documented in list.h
 *----------------------------------------------------------*/

void ListInitialise( LIST_t * const List )
{
	/* The list structure contains a list item which is used to mark the
	end of the list.  To initialise the list the list end is inserted
	as the only list entry. */
	List->Index = ( ListNode_t * ) &( List->ListEnd );			/*lint !e826 !e740 The mini list structure is used as the list end to save RAM.  This is checked and valid. */

	/* The list end value is the highest possible value in the list to
	ensure it remains at the end of the list. */
	List->ListEnd.NodeValue = portMAX_DELAY;

	/* The list end next and previous pointers point to itself so we know
	when the list is empty. */
	List->ListEnd.Next = ( ListNode_t * ) &( List->ListEnd );	/*lint !e826 !e740 The mini list structure is used as the list end to save RAM.  This is checked and valid. */
	List->ListEnd.Previous = ( ListNode_t * ) &( List->ListEnd );/*lint !e826 !e740 The mini list structure is used as the list end to save RAM.  This is checked and valid. */

	List->NumberOfNodes = ( UBaseType_t ) 0U;
}
/*-----------------------------------------------------------*/

void ListInitialiseNode( ListNode_t * const Node )
{
	/* Make sure the list item is not recorded as being on a list. */
	Node->Container = ( ( void* ) 0 );
}
/*-----------------------------------------------------------*/

void ListInsertEnd( LIST_t * const List, ListNode_t * const NewListNode )
{
ListNode_t * const Index = List->Index;

	/* Insert a new list item into List, but rather than sort the list,
	makes the new list item the last item to be removed by a call to
	listGET_OWNER_OF_NEXT_ENTRY(). */
	NewListNode->Next = Index;
	NewListNode->Previous = Index->Previous;

	Index->Previous->Next = NewListNode;
	Index->Previous = NewListNode;

	/* Remember which list the item is in. */
	NewListNode->Container = ( void * ) List;

	( List->NumberOfNodes )++;
}
/*-----------------------------------------------------------*/

void ListInsert( LIST_t * const List, ListNode_t * const NewListNode )
{
ListNode_t *Iterator;
const UBaseType_t ValueOfInsertion = NewListNode->NodeValue;

	/* Insert the new list item into the list, sorted in NodeValue order.

	If the list already contains a list item with the same item value then the
	new list item should be placed after it.  This ensures that TCB's which are
	stored in ready lists (all of which have the same NodeValue value) get a
	share of the CPU.  However, if the NodeValue is the same as the back marker
	the iteration loop below will not end.  Therefore the value is checked
	first, and the algorithm slightly modified if necessary. */
	if( ValueOfInsertion == portMAX_DELAY )
	{
		Iterator = List->ListEnd.Previous;
	}
	else
	{
		/* *** NOTE ***********************************************************
		If you find your application is crashing here then likely causes are
		listed below.  In addition see http://www.freertos.org/FAQHelp.html for
		more tips, and ensure configASSERT() is defined!
		http://www.freertos.org/a00110.html#configASSERT

			1) Stack overflow -
			   see http://www.freertos.org/Stacks-and-stack-overflow-checking.html
			2) Incorrect interrupt priority assignment, especially on Cortex-M
			   parts where numerically high priority values denote low actual
			   interrupt priorities, which can seem counter intuitive.  See
			   http://www.freertos.org/RTOS-Cortex-M3-M4.html and the definition
			   of configMAX_SYSCALL_INTERRUPT_PRIORITY on
			   http://www.freertos.org/a00110.html
			3) Calling an API function from within a critical section or when
			   the scheduler is suspended, or calling an API function that does
			   not end in "FromISR" from an interrupt.
			4) Using a queue or semaphore before it has been initialised or
			   before the scheduler has been started (are interrupts firing
			   before vTaskStartScheduler() has been called?).
		**********************************************************************/

		for( Iterator = ( ListNode_t * ) &( List->ListEnd ); Iterator->Next->NodeValue <= ValueOfInsertion; Iterator = Iterator->Next ) /*lint !e826 !e740 The mini list structure is used as the list end to save RAM.  This is checked and valid. */
		{
			/* There is nothing to do here, just iterating to the wanted
			insertion position. */
		}
	}

	NewListNode->Next = Iterator->Next;
	NewListNode->Next->Previous = NewListNode;
	NewListNode->Previous = Iterator;
	Iterator->Next = NewListNode;

	/* Remember which list the item is in.  This allows fast removal of the
	item later. */
	NewListNode->Container = ( void * ) List;

	( List->NumberOfNodes )++;
}
/*-----------------------------------------------------------*/

UBaseType_t ListRemove( ListNode_t * const NodeToRemove )
{
/* The list item knows which list it is in.  Obtain the list from the list
item. */
LIST_t * const List = ( LIST_t * ) NodeToRemove->Container;

	NodeToRemove->Next->Previous = NodeToRemove->Previous;
	NodeToRemove->Previous->Next = NodeToRemove->Next;

	/* Make sure the index is left pointing to a valid item. */
	if( List->Index == NodeToRemove )
	{
		List->Index = NodeToRemove->Previous;
	}
	else
	{

	}

	NodeToRemove->Container = ( ( void* ) 0 );
	( List->NumberOfNodes )--;

	return List->NumberOfNodes;
}
/*-----------------------------------------------------------*/








/* 以下是测试链表的测试函数 */
#include "rtos_list.h"

static void task_1(void)
{
	printf("task1 run\r\n");
}
static void task_2(void)
{
	printf("task2 run\r\n");
}
static void task_3(void)
{
	printf("task3 run\r\n");
}

void List_Test(void)
{
	// 创建链表和节点
	static LIST_t MyList;
	static ListNode_t ListNode1, ListNode2, ListNode3;

    // 初始化链表
    ListInitialise( &MyList );

    // 初始化节点
    ListInitialiseNode( &ListNode1 );
    ListInitialiseNode( &ListNode2 );
    ListInitialiseNode( &ListNode3 );

    // 设置节点值
    ListNode1.NodeValue = 10;
    ListNode2.NodeValue = 20;
    ListNode3.NodeValue = 5;

	// 设置节点对象
    ListNode1.Owner = task_1;
    ListNode2.Owner = task_2;
    ListNode3.Owner = task_3;

    // 插入节点（按值排序）
    ListInsert( &MyList, &ListNode1 );  // 链表: 10
    ListInsert( &MyList, &ListNode2 );  // 链表: 10 -> 20
    ListInsert( &MyList, &ListNode3 );  // 链表: 5 -> 10 -> 20

    // 遍历链表
    ListNode_t *Current = ( ListNode_t * ) &( MyList.ListEnd );
    while( Current->Next != ( ListNode_t * ) &( MyList.ListEnd ) )
	{
        Current = Current->Next;
        printf("NodeValue: %d\n", ( int ) Current->NodeValue );
    }
	printf("********\r\n");

    // 遍历链表
    Current = ( ListNode_t * ) &( MyList.ListEnd );
    while( Current->Next != ( ListNode_t * ) &( MyList.ListEnd ) )
	{
		Current = Current->Next;
		((void(*)(void))Current->Owner)();
    }
	printf("********\r\n");

    // 删除节点
    ListRemove( &ListNode2 );  // 链表: 5 -> 10
	
	// 遍历链表
    Current = ( ListNode_t * ) &( MyList.ListEnd );
    while( Current->Next != ( ListNode_t * ) &( MyList.ListEnd ) )
	{
		Current = Current->Next;
		((void(*)(void))Current->Owner)();
    }
	printf("********\r\n");
}
